package com.epigeon.amadeo.impl;

import java.util.LinkedList;
import java.util.List;
import java.util.Map;

import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.PacketListener;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.filter.MessageTypeFilter;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.Packet;
import org.jivesoftware.smack.packet.Presence;
import org.jivesoftware.smack.util.StringUtils;

import com.epigeon.amadeo.engine.Engine;
import com.epigeon.amadeo.input.ActiveInput;
import com.epigeon.amadeo.input.PassiveInput;
import com.epigeon.amadeo.model.Message;
import com.epigeon.amadeo.model.XMPPConnectionMessage;
import com.epigeon.amadeo.model.XMPPMessage;
import com.epigeon.amadeo.modifier.Modifier;
import com.epigeon.amadeo.output.Output;

public class XMPPConnectionInput implements ActiveInput, Output, PacketListener {

	public static final String MESSAGE_TYPE_CONNECT = "connectMessage";
	public static final String MESSAGE_TYPE_DISCONNECT = "disconnectMessage";
	public static final String MESSAGE_TYPE_SEND = "sendMessage";
	public static final String MESSAGE_TYPE_RECEIVE = "receiveMessage";
	
	private List<Modifier> modifiers = new LinkedList<Modifier>();	
	
	private XMPPConnection connection;
	private Message message;
	
	public String key;
	
	@Override
	public Message getMessage() {
		return message;
	}

	@Override
	public void setParameters(Map<String, String> parameterMap) {
	}

	@Override
	public List<Modifier> getModifierList() {
		return this.modifiers;		
	}

	@Override
	public void addModifier(Modifier modifier) {
		this.modifiers.add(modifier);		
	}
	
	@Override
	public void putMessage(Message message) {
		if ( MESSAGE_TYPE_CONNECT.equals(message.getType()) ) {
			// connect to the xmpp server
			XMPPConnectionMessage connectionMessage = (XMPPConnectionMessage) message;
			this.connection = new XMPPConnection(new ConnectionConfiguration( connectionMessage.getHost(), Integer.parseInt(connectionMessage.getPort()), connectionMessage.getService() ));
			
			try {
				this.connection.connect();
				this.connection.login(connectionMessage.getUser(), connectionMessage.getPassword());
	            Presence presence = new Presence(Presence.Type.available);
	            connection.sendPacket(presence);
				PacketFilter filter = new MessageTypeFilter(org.jivesoftware.smack.packet.Message.Type.chat);
	            connection.addPacketListener(this, filter);
	            
			} catch (XMPPException e) {
				// TODO Handling exception - send back an error message
				e.printStackTrace();
			}
			
		} else if ( MESSAGE_TYPE_DISCONNECT.equals(message.getType()) ) {
			// disconnect from the server
			if ( this.connection != null && this.connection.isConnected() == true ) {
				this.connection.disconnect();
			}
		
		} else 	if ( MESSAGE_TYPE_SEND.equals(message.getType()) ) {
			// send a message
			if ( this.connection != null && this.connection.isConnected() == true ) {			
				XMPPMessage xmppMessage = (XMPPMessage) message;
				org.jivesoftware.smack.packet.Message toSend = new org.jivesoftware.smack.packet.Message(xmppMessage.getTo(), org.jivesoftware.smack.packet.Message.Type.chat);
				toSend.setBody(xmppMessage.getBody());
				connection.sendPacket(toSend);
			}
		}
	}

	@Override
	public void processPacket(Packet packet) {
		// process a message
		org.jivesoftware.smack.packet.Message receivedMessage = (org.jivesoftware.smack.packet.Message) packet;
		if (receivedMessage.getBody() != null) {
			String fromName = StringUtils.parseBareAddress(receivedMessage.getFrom());
			this.message = new XMPPMessage(XMPPConnectionInput.MESSAGE_TYPE_RECEIVE, this.key, fromName, "",  receivedMessage.getBody());
			Engine.getInstance().activeInputNotification(this, this.message);	
		}		
	}

	@Override
	public String getKey() {
		return this.key;
	}

	@Override
	public void setKey(String key) {
		this.key = key;
	}

	@Override
	public void addPassiveInput(PassiveInput input) {
		// nothing to do here
	}

	@Override
	public Message compose(List<Message> messages) {
		// nothing to do here
		return null;
	}

}
